Skip to content

feat(kap-server): add remote control device management - #4169

Merged
liruifengv merged 29 commits into
mainfrom
feat/remote-control-device-management
Oct 13, 2026
Merged

liruifengv merged 29 commits into
mainfrom
feat/remote-control-device-management

Conversation

@liruifengv

@liruifengv liruifengv commented Oct 10, 2026 •

Copy link
Copy Markdown
Collaborator

Requirement or Bug

Add kap-server APIs that let desktop manage Remote Control devices natively and clean up Remote Control sessions on logout.

Desktop companion: MoonshotAI/kimi-code-app#838

Bug Reproduction Steps

N/A

Root Cause

N/A

Code Changes

 Desktop renderer
   GET/POST /api/v1/remote-control
+  GET/PATCH/POST /api/v1/remote-control/devices*
+    RemoteControlDeviceClient
+      FileTokenStorage + resolveKimiRemoteControlAuth
+      POST /auth/exchange
+      in-memory cloud session cookie cache
+      /v1/remote/devices*

 OAuth logout (Kimi provider only, serialized per server)
+  tunnel hosted here → clear sessions, logout, answer first,
+    then tear the tunnel down after the response is flushed
+  starting/stopping → manager.disable() (starting is cancelled)
+  lock held by another process → cloud deactivate + wait for lock release
+  acquire the machine lock as a start gate (racing starts are
+    cloud-deactivated and waited out, then blocked while held)
+  remoteControlDevices.clear()
   IOAuthService.logout()
+  clear sessions again, release the start gate
  • Adds RemoteControlDeviceClient for cloud device listing, rename, and deactivate operations without exposing OAuth tokens or cloud cookies to the renderer. There is intentionally no delete endpoint: deactivation takes a device offline and offline devices stay listed without consuming quota.
  • Caches cloud session cookies only in Node memory, keyed by session generation, relay origin, and OAuth slot; a cloud 401 triggers one fresh exchange and one retry. All relay calls carry a 15s timeout, and clear() aborts in-flight requests.
  • Validates the full device-list payload and raises RemoteControlDeviceClientError on malformed shapes instead of silently reporting an empty list.
  • Maps alias validation failures to VALIDATION_FAILED and cloud/network failures to INTERNAL_ERROR, without triggering the local auth-required flow.
  • Registers every host with its own product identity (<productName>/<version>) instead of the historical hardcoded kimi-code/<server version>, and tags share URLs with the host platform (from=kimi_code_cli / kimi_code_desktop).
  • Surfaces the machine-wide single-instance lock in the status response (conflict) and in the already-running error details, resolving the lock live on every status read so a dead holder clears automatically.
  • Makes starting cancellable: disable() during an in-flight start aborts the connect loop and releases the lock instead of waiting forever for a settle that may never come (relay unreachable), and disable() now rejects when the tunnel close fails instead of swallowing the error into status.error. enable()/disable() calls are serialized through an internal queue, so a toggle queued behind a cancelled start is applied in order instead of being lost while both snapshot a stale off state.
  • Deactivating the current device stops the local tunnel (local-device detection reads the lock file, so an in-flight start is covered too) and waits briefly for the lock holder to release before responding.
  • On Kimi-provider logout, tears down this machine's Remote Control and clears cached cloud sessions (before and after the credential step). When this server hosts the tunnel, logout answers first and closes the tunnel after the response is flushed, so a logout sent through the Remote Control link still receives its envelope; otherwise the tunnel is stopped first and the machine lock is held as a start gate so no process can register again until the credential is discarded (a start racing the gate is cloud-deactivated and waited out). A cleanup failure aborts the logout before the credential is touched. Logouts of other providers leave Remote Control untouched.
  • Documents the status/toggle and device endpoints in docs/{en,zh}/reference/server-api.md.
  • Exports loadOrCreateServerToken from @moonshot-ai/kap-server so hosts (e.g. the desktop app's embedded server) can provision the shared server.token that Remote Control authentication requires, instead of replicating the private-file write logic.

Behavior Changes and Affected Users

Behavior Before After Who relies on the old behavior Escape hatch
Remote Control device management API No kap-server routes for listing or managing devices /api/v1/remote-control/devices* proxies the cloud device list/rename/deactivate APIs for authenticated local clients None; this is a new API surface None needed
Remote Control client_version registration Every kap-server host and CLI web host registered as kimi-code/<version> CLI registers kimi-code-cli/<version>, desktop registers kimi-code-desktop/<version> (CLI call sites share one app-level constant) Relay treats it as an opaque string: stored as VARCHAR(64), returned in the device list, used as a trace label; no parsing, version gating, or fingerprinting (device identity is device_id). Verified against the relay source None needed
Remote Control toggle on a machine already hosting an instance The enable attempt failed with a plain-text error The status response and the 40928 error carry the lock holder (pid, url, started_at) so clients can render a structured conflict Clients that parsed the free-text error The text error is still present; only structured fields were added
RemoteControlManager.disable() during an in-flight start Waited indefinitely for the start to settle (hangs forever when the relay is unreachable) Cancels the start, releases the lock, returns off; the pending enable() rejects with "disabled while starting" None; hanging was never useful None needed
RemoteControlManager.disable() failure Stop failures were stored in status.error and disable() resolved disable() rejects on stop failure Callers that assumed disable() never throws (close() already guards) None; surfacing the failure is the point
OAuth logout while Remote Control is enabled Logout cleared OAuth credentials while the tunnel and in-memory cloud session could remain active For the Kimi provider, logout first takes this machine's Remote Control offline (local tunnel or another process's via cloud deactivation), then holds the machine lock so starts are blocked until the credential is discarded, and clears cached cloud sessions; cleanup failure blocks logout before the credential is touched. Other providers' logouts no longer touch Remote Control Desktop and web users logging out with Remote Control enabled None; this is intentional cleanup

Affected modules and coverage:

  • packages/remote-control: exchange/cookie caching, 401 refresh and retry limit, OAuth slot selection, clear() invalidation and in-flight abort, request timeout, payload validation and field projection, manager start cancellation, disable failure, serialized toggles, and handshake abortion on close — 38 tests passed.
  • packages/kap-server: device routes, alias validation, cloud error mapping, API surface snapshot, logout ordering/provider scoping/foreign-holder deactivation/start gating/serialization/respond-first teardown, registration identity, live conflict resolution, deactivate lock wait and in-flight start cancellation — 25 tests passed (full package 1436 passed, 1 skipped; the unrelated GlobalSearchService case is flaky in parallel runs and passes standalone).
  • apps/kimi-code: CLI web remote-control call sites and close-reason handling — 83 tests passed.
  • pnpm --filter @moonshot-ai/remote-control run typecheck && pnpm --filter @moonshot-ai/kap-server run typecheck passed.

Checklist

No changeset was added at the requester's direction; the behavior changes are declared in the table above.

  • I have read the CONTRIBUTING document.
  • I have linked a related issue (external PRs: issue must have a maintainer's /approve).
  • I have added tests that prove my feature works.
  • The behavior-change table above is complete, and every removed behavior or flipped default is named in the changeset and either has an escape hatch or was explicitly approved by a maintainer in this PR.
  • Ran gen-changesets skill, or this PR needs no changeset.
  • Ran gen-docs skill, or this PR needs no doc update.

@changeset-bot

changeset-bot Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 732b45a

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copilot AI balanced review requested due to automatic review settings October 10, 2026 09:18

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Pending operations can survive logout, malformed responses can silently discard devices, and outbound requests can hang indefinitely.

3 open findings
What changed in this PR

Adds native Remote Control device management to kap-server and cleans up Remote Control state during OAuth logout.

Changes:

  • Adds cloud-backed device listing, renaming, deactivation, and deletion APIs.
  • Caches cloud sessions and retries once after a 401.
  • Disables Remote Control and clears sessions before logout.
File Description
packages/​remote-control/​src/​device-client.ts Implements device client and session caching.
packages/​remote-control/​src/​index.ts Exports the device client.
packages/​remote-control/​test/​remote-control.test.ts Tests device operations and session behavior.
packages/​kap-server/​src/​start.ts Instantiates the client and selects registration identity.
packages/​kap-server/​src/​routes/​remoteControl.ts Adds device management routes.
packages/​kap-server/​src/​routes/​registerApiV1Routes.ts Wires Remote Control dependencies into OAuth routes.
packages/​kap-server/​src/​routes/​oauth.ts Cleans up Remote Control before logout.
packages/​kap-server/​src/​protocol/​rest-remote-control.ts Defines device API schemas.
packages/​kap-server/​test/​remoteControl.test.ts Tests routes, logout ordering, and identity behavior.
packages/​kap-server/​test/​__snapshots__/​apiSurface.snapshot.test.ts.snap Records the expanded API surface.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/remote-control/src/device-client.ts
Comment thread packages/remote-control/src/device-client.ts Outdated
Comment thread packages/remote-control/src/device-client.ts
The share link's from query parameter was hardcoded to kimi_code_cli, so
links created by the desktop app were mislabeled as CLI traffic.

buildRemoteControlUrl now takes the source explicitly and
RemoteControlOptions carries it as urlSource; kap-server threads
hostIdentity.platform through, so desktop hosts produce
from=kimi_code_desktop while CLI hosts keep from=kimi_code_cli.
…ctivated or deleted

The device management routes only called the cloud API. When the target
device is the machine itself, the local tunnel kept running: after the
relay drops it, the client reconnects and re-registers, so the device
came back online (or was recreated after a delete) and the local status
never returned to off.

After a successful cloud deactivate/delete of the current device, the
routes now also disable the local tunnel manager.
Device removal is collapsed to a single deactivate verb: the desktop UI
deactivates devices instead of deleting them, so the DELETE
/remote-control/devices/{id} route and the device client's deleteDevice
go away before this API ever ships.
The enable route now returns the RemoteControlAlreadyRunningError holder
(pid, local origin, device id, url, started_at) in the error envelope's
details, documented with a details schema, so desktop can render a
structured conflict state instead of the raw message.
The manager now surfaces the holder when its last enable error is an
already-running lock conflict, and GET /remote-control returns it as a
structured conflict field, so clients can present the conflict state
proactively instead of parsing the error message.
…atus

GET /remote-control now re-inspects the machine lock whenever the
manager is off: a live holder is reported as the conflict even without
a prior enable attempt in this process, and a stored conflict plus its
error text are dropped once the holder's process is gone. Panel state
refreshes such as after device deactivation now reflect reality.
…ce deactivation

When the deactivated device is the machine's own and the lock is held
by another live process (e.g. a CLI instance whose tunnel the relay is
about to terminate with user_requested), the route now polls the lock
for up to two seconds before responding, so a client's immediately
following status read sees the settled conflict-free state.
…evice-management

# Conflicts:
#	packages/kap-server/src/start.ts
@liruifengv
liruifengv marked this pull request as ready for review October 12, 2026 10:57
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-13T07:47:53.243608Z 732b45a Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@liruifengv

Copy link
Copy Markdown
Collaborator Author

@codex

@pkg-pr-new

pkg-pr-new Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
pnpm dlx https://pkg.pr.new/@moonshot-ai/kimi-code@732b45a
npx https://pkg.pr.new/@moonshot-ai/kimi-code@732b45a

commit: 732b45a

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ed43353053

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/kap-server/src/start.ts
Comment thread packages/kap-server/src/routes/oauth.ts Outdated
Comment thread packages/kap-server/src/routes/remoteControl.ts Outdated
Comment thread packages/remote-control/src/device-client.ts Outdated
Comment thread packages/remote-control/src/device-client.ts
Comment thread packages/kap-server/src/routes/remoteControl.ts
Comment thread packages/kap-server/src/routes/oauth.ts Outdated
Comment thread packages/kap-server/src/routes/oauth.ts Outdated
Comment thread packages/kap-server/src/routes/oauth.ts Outdated
@liruifengv

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a638c64fa4

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/remote-control/src/remote-control.ts
Comment thread packages/kap-server/src/routes/remoteControl.ts Outdated
Comment thread packages/kap-server/src/routes/oauth.ts Outdated
Comment thread packages/remote-control/src/manager.ts Outdated
@liruifengv

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cf9a27d328

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/kap-server/src/routes/oauth.ts Outdated
Comment thread packages/kap-server/src/routes/remoteControl.ts
@liruifengv

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9f62801999

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/kap-server/src/routes/oauth.ts Outdated
Comment thread packages/kap-server/src/routes/remoteControl.ts Outdated
@liruifengv

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1955b5dfc1

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/kap-server/src/routes/oauth.ts Outdated
Comment thread packages/kap-server/src/routes/remoteControl.ts Outdated
Comment thread packages/kap-server/src/routes/remoteControl.ts Outdated
Comment thread packages/remote-control/src/device-client.ts Outdated
@liruifengv

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: de8830eedf

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/remote-control/src/remote-control.ts
Comment thread packages/kap-server/src/routes/oauth.ts
@liruifengv

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 34f23dd53f

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/remote-control/src/manager.ts
@liruifengv

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 442aecffb8

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/kap-server/src/routes/oauth.ts
Comment thread packages/kap-server/src/routes/oauth.ts Outdated
@liruifengv

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ab76e38658

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/kap-server/src/routes/remoteControl.ts
Comment thread packages/remote-control/src/manager.ts Outdated
Comment thread packages/kap-server/src/routes/oauth.ts
@liruifengv

Copy link
Copy Markdown
Collaborator Author

@codex review

Comment thread packages/kap-server/src/start.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d35a762085

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/remote-control/src/manager.ts
Comment thread packages/kap-server/src/routes/remoteControl.ts
Comment thread packages/remote-control/src/manager.ts
sailist
sailist previously approved these changes Oct 13, 2026
@liruifengv

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🎉

Reviewed commit: 732b45abdc

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@liruifengv
liruifengv merged commit c69bd6c into main Oct 13, 2026
16 checks passed
@liruifengv
liruifengv deleted the feat/remote-control-device-management branch October 13, 2026 09:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants